function Window() {

    /**
    * Css prefix pointing to the main window class. Prefix + specific suffix will form className of
    * desired element.
    *
    * @private
    * @property cssPrefix
    * @type     String
    * @default  messWindow
    */
    this.cssPrefix = "Window";

 	/**
    * Reference to DOM element representing window header
    *
    * @private
    * @property windowHeaderDom
    * @type     DOM
    * @default  null
    */
    this.windowHeaderDom = null;

    /**
    * Reference to DOM window title node.
    *
    * @private
    * @property windowHeaderTitle
    * @type     DOM
    * @default  null
    */
    this.windowHeaderTitle = null;
    
    /**
    * Reference to DOM element representing window header options box
    *
    * @private
    * @property windowHeaderButtons
    * @type     DOM
    * @default  null
    */
    this.windowHeaderButtonsDom = null;

    /**
    * Reference to DOM element representing window content element
    *
    * @private
    * @property windowContentDom
    * @type     DOM
    * @default  null
    */
    this.windowContentDom = null;

    /**
    * Window title visible in header.
    *
    * @private
    * @property windowTitle
    * @type     String
    * @default  null;
    */
    this.windowTitle = null;

    /**
    * Window icon ivisble in header
    *
    * @private
    * @property  windowIcon
    * @type      String
    * @default   null
    */
    this.windowIcon = null;

    /**
    * Window icon box dom object
    *
    * @private
    * @property  windowIconDom
    * @type      {DOM}
    * @default   null
    */
    this.windowIconDom = null;
  
    /**
	 * Size in pixels of window header element
	 * 
	 * @private
	 * @property  headerSize
	 * @type      Number
	 * @default   20
	 */
	this.headerSize = new Number(20);
	
    /**
    * Buttons collection
    *
    * @private
    * @property buttons
    * @type     List
    * @default  empty list
    */
    this.buttons = null;
    
	/**
	 * Resize button reference variable
	 * 
	 * @private
	 * @property  resizeButton
	 * @type      ResizeButton
	 * @default   null
	 */
	this.resizeButton = null;
	
    /**
    * Shrinked flag - true if window is in shrinked state, false otherwise
    *
    * @private
    * @property  shrinked
    * @type      Boolean
    * @default   false
    */
    this.shrinked = false;
    
    /**
    * Maximized flag - true if window is in maximized state, false otherwise
    *
    * @private
    * @property  maximized
    * @type      Boolean
    * @default   false
    */
    this.maximized = false; 
    

	/**
	 * Mouse over flag. Indicates if window has mouseover the header.
	 * 
	 * @private
	 * @property  mouseOver
	 * @type      Boolean
	 * @default   false
	 */
	this.mouseOver = false;
	
    /**
    * Window object (hidden), remembered during shrink operation. Will be used to rewrite
    * variables during expand operation. Shrink creates new 'temporary' window object. Expand
    * tries to return window into previous state (before shrinking) updating dimensions of neighbour panels
    * to fit this one.
    *
    * @private
    * @property  windowClone
    * @type      Window
    * @default   null
    */
    this.windowClone = null;

    /**
    * Window child control. Child control and it's contents will be rendered (and attached to)
    * the window content dom tree. Window can have an inside panel of windows, tree view or some
    * other, mess specific control.
    *
    * @private
    * @property control
    * @type     MessUIElement
    * @default  null
    */
    this.control = null;
    
    this.CONTAINER_CSS_SUFFIX = "Container";
    this.CONTAINER_SHRINKED_CSS_SUFFIX = this.CONTAINER_CSS_SUFFIX + "Shrinked";
    this.HEADER_CSS_SUFFIX = "Header"
    this.HEADER_OVER_CSS_SUFFIX = this.HEADER_CSS_SUFFIX + "Over";
    this.HEADER_SHRINKED_CSS_SUFFIX = this.HEADER_CSS_SUFFIX + "Shrinked";
    this.HEADER_SHRINKED_OVER_CSS_SUFFIX = this.HEADER_SHRINKED_CSS_SUFFIX + "Over";
    this.HEADER_VERTICAL_CSS_SUFFIX = "HeaderVertical"
    this.HEADER_VERTICAL_OVER_CSS_SUFFIX = this.HEADER_VERTICAL_CSS_SUFFIX + "Over";
    this.TITLE_CSS_SUFFIX = "Title";
    this.ICON_CSS_SUFFIX = "Icon";
    this.BUTTONS_BOX_CSS_SUFFIX = "ButtonsBox";
    this.BUTTONS_BOX_VERTICAL_CSS_SUFFIX = this.BUTTONS_BOX_CSS_SUFFIX + "Vertical";
    this.CONTENT_CSS_SUFFIX = "Content";
}
Window.prototype = new MessUIElement();
Window.prototype.toString = function() { return "js.mess.ui.controls.windows.Window"; };
MessUIElement.prototype.addTagMapping("window", "Window");



    /**
    * Function responsible to build window dom representation and do any necessary initialization routines.
    *
    * @private
    * @method build
    */
    Window.prototype.build = function() {

        // initialize control
        this.initControl();
        // build dom
        this.buildDOMObject();
        // attach events
        this.attachEventHandlers();
    };

    /**
    * Builds Window DOM object
    *
    * @private
    * @method buildDOMObject
    */
    Window.prototype.buildDOMObject = function() {
	
		if (this.getTheme() === null) {
			this.setTheme("Default");
		}

		if (this.isShrinked()) {
		// build shrinked representation on startup
			this.buildDOMObjectShrinked();
		}
		else {
		// build window normal representaion
			this.buildDOMObjectExpanded();
            this.buildButtonsBox();
        }
    };

	/**
	* Builds window object in "expanded" state.
	*
	* @private
	* @method  buildDOMObjectExpanded
	*/
	Window.prototype.buildDOMObjectExpanded = function() {
	       
	    // build container
		var container = this.buildContainerDOM(); 
			
		// window header
		container.appendChild(this.buildWindowHeaderDOM());
			// icon
            this.windowHeaderDom.appendChild(this.buildWindowHeaderIconDOM());
            // title
			this.windowHeaderDom.appendChild(this.buildWindowHeaderTitleDOM());
			// buttons box
			this.windowHeaderDom.appendChild(this.buildWindowHeaderButtonsBoxDOM());

		// window content
		container.appendChild(this.buildWindowContentDOM());
		
		// update dom object
		this.updateDomObject(container);
	};
	
    /**
	* Builds window object in "shrinked" state. Different behaviour for horizontal and vertical windows
	*
	* @private
	* @method  buildDOMObjectShrinked
	*/
    Window.prototype.buildDOMObjectShrinked = function() {
		
        // build container
        var container = this.buildContainerDOM();
        // window header
        container.appendChild(this.buildWindowHeaderDOM());
            if (this.isHorizontal()) {
                // title
                this.windowHeaderDom.appendChild(this.buildWindowHeaderTitleDOM());
            }
            // buttons box
            this.windowHeaderDom.appendChild(this.buildWindowHeaderButtonsBoxDOM());

        // rebuild options box
        this.buildButtonsBox();
        // attach event handlers
        this.attachEventHandlers();
        // save dom object
        this.setDomObject(container);

        if (this.isVertical()) {
            this.setHeight( this.parent.getHeight() - 2 );
            this.setHeight( this.getHeight(), this.windowHeaderDom );
        }

        this.parent.replaceControl(this);
    };

	/**
	 * Builds window container DOM object
	 * 
	 * @private
	 * @method  buildContainerDOM
	 * @return  {DOM} container DOM representation
	 */
	Window.prototype.buildContainerDOM = function() {
	 	
	 	var container = DIV();
	 		container.id = this.id;
	        container.className = this.getContainerCssClass();

	 	return container;	
	};

    /**
    * Method build window child controls, funcional and inner ones
    *
    * @private
    * @method   buildChildControls
    */
    Window.prototype.buildChildControls = function() {

        // buttonx box
        this.buildButtonsBox(true);
        // inner control
        this.buildChildControl();
    }

    /**
    * Refresh window state.
    *
    * @public
    * @method  invalidate
    */
    Window.prototype.invalidate = function() {

        // refresh buttons
        this.buildButtonsBox(true);

        // refresh inner control
        if (this.control) {
            this.control.invalidate();
        }
    };

    /**
	 * Returns css class for the container dom object
	 * 
	 * @private
	 * @method  getContainerCssClass
	 * @return  {String} css class
	 */
	Window.prototype.getContainerCssClass = function() {
		
		var suffix = this.CONTAINER_CSS_SUFFIX;
		if (this.isShrinked()) {
			suffix = this.CONTAINER_SHRINKED_CSS_SUFFIX;
		}
		
		return this.getCssPrefix() + suffix;
	};
	 
	 /**
	  * Build window header DOM object
	  * 
	  * @private
	  * @method  buildWindowHeaderDOM
	  * @return  {DOM}  window header dom representation
	  */
	Window.prototype.buildWindowHeaderDOM = function() {
		
		var header = DIV();
			header.id = this.id+":header";
			header.className = this.getWindowHeaderCssClass();
            this.setHeight(this.headerSize-2, header); // -2 for borders

        eventUtil.disableTextSelectionEvent(header);
        
        this.windowHeaderDom = header;
		return header;
	};
	
	/**
	 * Returns css class name for window header dom object
	 * 
	 * @private
	 * @method  getWindowHeaderCssClass
	 * @return   {String} css class
	 */
	Window.prototype.getWindowHeaderCssClass = function() {
		
		var suffix;

		if (this.isShrinked()) {
		// class for shrinked window
            if (this.isHorizontal()) {
                suffix = this.HEADER_SHRINKED_CSS_SUFFIX;
                if (this.hasMouseOver()) {
                    suffix = this.HEADER_SHRINKED_OVER_CSS_SUFFIX;
                }
            }
            else {
                suffix = this.HEADER_VERTICAL_CSS_SUFFIX;
                if (this.hasMouseOver()) {
                    suffix = this.HEADER_VERTICAL_OVER_CSS_SUFFIX;
                }
            }
        }
		else {
		// class for expanded window
			suffix = this.HEADER_CSS_SUFFIX;
			if (this.hasMouseOver()) {
				suffix = this.HEADER_OVER_CSS_SUFFIX;
			}		
		}
		
		return this.getCssPrefix() + suffix;
	};

    /**
    * Build window header icon DOM object
    *
    * @private
    * @method  buildWindowHeaderIconDOM
    * @return  {DOM} header icon dom representation
    */
    Window.prototype.buildWindowHeaderIconDOM = function() {
        var iconDiv = DIV();
            iconDiv.id = this.id+":icon";
            iconDiv.className = this.getWindowHeaderIconCssClass();

        if (this.windowIcon) {
            var icon = IMG("style/themes/default/controls/window/themes/"+this.getTheme()+"/img/icons/"+this.windowIcon);
            icon.id = iconDiv.id + ":image"
            iconDiv.appendChild(icon);
        }

        this.windowIconDom = iconDiv;
        return iconDiv;
    }

    /**
    * Get window icon dom css selector class
    *
    * @private
    * @method  getWindowHeaderIconCssClass
    * @return  {String} css class
    */
    Window.prototype.getWindowHeaderIconCssClass = function() {
        var suffix = this.ICON_CSS_SUFFIX; 
		return this.getCssPrefix() + suffix;
    }

    /**
	 * Build window header title DOM object
	 * 
	 * @private
	 * @method  buildWindowHeaderTitleDOM
	 * @return  {DOM} header title dom representation
	 */
	Window.prototype.buildWindowHeaderTitleDOM = function() {
		
		var title = DIV();
			title.id = this.id+":title";
			title.className = this.getWindowHeaderTitleCssClass();
		
		if (!(this.isShrinked() && this.isVertical())) {
		// no text in shrinked vertical windows
            var text = TEXT(this.windowTitle);
            //text.id = title.id+":text"
            title.appendChild(text);
		}
		
		this.windowTitleDom = title;	
		return title;	
	};

	/**
	 * Return window header title element css class
	 * 
	 * @private
	 * @method  getWindowHeaderTitleCssClass
	 * @return  {String} css class
	 */
	Window.prototype.getWindowHeaderTitleCssClass = function() {
		
		var suffix = this.TITLE_CSS_SUFFIX; 
		return this.getCssPrefix() + suffix;
	};
	
	/**
	 * Build window header buttons box DOM object
	 * 
	 * @private
	 * @method  buildWindowHeaderButtonsBoxDOM
	 * @return  {DOM} buttons box dom representation
	 */
	Window.prototype.buildWindowHeaderButtonsBoxDOM = function() {
		
		var box = DIV();
			box.id = this.id+":buttons";
			box.className = this.getWindowHeaderButtonsCssClass();
		
		this.windowHeaderButtonsDom = box;	
		return box;
	};
	
	/**
	 * Returns window header buttons box css class name
	 * 
	 * @private
	 * @method  getWindowHeaderButtonsCssClass
	 * @return  {String} css class
	 */
	Window.prototype.getWindowHeaderButtonsCssClass = function() {
		
		var suffix = this.BUTTONS_BOX_CSS_SUFFIX; 
		try {
			if (this.isShrinked() && this.isVertical()) {
				suffix = this.BUTTONS_BOX_VERTICAL_CSS_SUFFIX;
			}
		}
		catch (ex) {}
		return this.getCssPrefix() + suffix;	
	};
	
	/**
	 * Build window content DOM representation
	 * 
	 * @public
	 * @method  buildWindowContentDOM
	 * @return  {DOM} window content dom
	 */
	Window.prototype.buildWindowContentDOM = function() {
		
		var content = DIV();
			content.id = this.id+":content";
			content.className = this.getCssPrefix() + this.CONTENT_CSS_SUFFIX;

        this.windowContentDom = content;
		
    	this.setControlHeight( this.parent.getHeight() );
		this.setControlWidth( this.parent.getWidth() );

		return content;
	};
	  
	/**
	 * Update window DOM object
	 * 
	 * @public
	 * @method  updateDomObject
	 */ 
	Window.prototype.updateDomObject = function(object) {
		
		// docked window
		this.setDomObject(object);
	};
	
	 
    /**
    * Builds window control box (close, minimize, shrink.. etc)
    *
    * @private
    * @method buildControlBox
    * @param  {Boolean} reset  states if in reset mode (remove all buttons before adding new)
    */
    Window.prototype.buildButtonsBox = function(mode) {

        var args = Window.prototype.buildButtonsBox.arguments;
		var refresh = false;
		if (args.length === 1) {
			refresh = args[0];	
		}
		

		if (this.buttons && !this.buttons.isEmpty()) {
			if (refresh) {
			// refresh buttons
				for (var it = this.buttons.iterator(); it.hasNext();) {
	        		this.refreshButton(it.next());
	        	}		
			}
			else {
			// build buttons from scratch	
				for (var it = this.buttons.iterator(); it.hasNext();) {
	        		this.buildButton(it.next());
	        	}	
			}
		}
    };
    
	/**
	 * Refresh button object - change representation according to situation
	 * 
	 * @private
	 * @method   refreshButton
	 * @param    {ActionButton}   button object to refresh
	 */
	Window.prototype.refreshButton = function(button) {
		
		button.setButtonRepresentation();
	};
	 
    /**
     * Build button object, performing any necessary initialization routines
     * 
     * @private
     * @method  buildButton
     * @param   {ActionButton}  button object to build
     */
     Window.prototype.buildButton = function(button) {
     
     	button.setParent(this);
     	button.build();
		//render standard buttons in container box
   		if (button.isStandardButton()) {
			this.windowHeaderButtonsDom.appendChild(button.render());
   		}	
   		else {
   		// handle special buttons
   		
   			// resize button
   			if (button instanceof ResizeButton) {
   				// set button position
   				this.resizeButton = button; // remember resize button in local variable
   				button.updateButtonPosition();
   				this.windowContentDom.appendChild(button.render());
   			}
   		}	
     };
     
    /**
     * Add button - buttons box element.
     * 
     * @public
     * @method  addButton
     * @param   {ActionButton}  button   button to add to buttons collection
     */
     Window.prototype.addButton = function(button) {

         if (!this.buttons) {
             this.buttons = new List();
         }
         this.buttons.add(button);
     };

    /**
    * Adds window child control object. Called during object initialization by
    * XmlDataParser routines.
    *
    * @public
    * @method  addControl
    * @param   {Object} control
    */
    Window.prototype.addControl = function(control) {

        if (control instanceof ActionButton) {
        // window button
            this.addButton(control);
        }
        else {
        // inner control
            this.control = control;
        }

        return control;
    }
    /**
	 * Build child control if it has any
	 * 
	 * @private
	 * @method  buildChildControl
	 */
	Window.prototype.buildChildControl = function() {

		if (this.control !== null) {
            
            // init parent and theme, build object
            this.buildChildControlObject(this.control);
            // update dom tree
	        this.windowContentDom.appendChild( this.control.render() );
            // try building control children
            try {
                this.control.buildChildControls();
            }
            catch (ex) {}
        }

        return this.control;	
	};
	
    /**
    * Attaches basic event handlers for window object
    *
    * @private
    * @method attachEventHandlers
    */
    Window.prototype.attachEventHandlers = function() {

		// mouse over
	    eventUtil.addEventHandler(this.windowHeaderDom, "mouseover", Window.prototype.onMouseOverHandler); 
        // mouse out
		eventUtil.addEventHandler(this.windowHeaderDom, "mouseout", Window.prototype.onMouseOutHandler); 
		// doubleclick on header
		eventUtil.addEventHandler(this.windowHeaderDom, "dblclick", Window.prototype.onDoubleClickHandler);
	};

    /**
    * EVENT, onMouseOver event handler - handles moveOver event for window header
    *
    * @event
    * @method  onMouseOverHandler
    */
    Window.prototype.onMouseOverHandler = function() {

		var oEvent = eventUtil.getEvent();
		var oSource = eventUtil.getSource(oEvent);

        var window = null;
        var target = Window.prototype.objects.get(oSource.id);

        if (target instanceof Window) {
        // window receiving event
            window = target;
        }
        else if (target instanceof ActionButton) {
        // button receiving event
            window = target.getParent();
        }

        if (window !== null) {
        	window.setMouseOver(true);
            window.windowHeaderDom.className = window.getWindowHeaderCssClass();
        }
    };

    /**
    * EVENT, onMouseOut event handler - handles moveOut event for window header
    *
    * @event
    * @method  onMouseOutHandler
    */
    Window.prototype.onMouseOutHandler = function() {

		var oEvent = eventUtil.getEvent();
		var oSource = eventUtil.getSource(oEvent);

        var window = null;
        var target = Window.prototype.objects.get(oSource.id);

        if (target instanceof Window) {
        // window receiving event
            window = target;
        }
        else if (target instanceof ActionButton) {
        // button receiving event
            window = target.getParent();
        }

        if (window !== null) {
        	window.setMouseOver(false);
            window.windowHeaderDom.className = window.getWindowHeaderCssClass();
        }
    };
	
	/**
	* Handles double click on window header (shrink action)
	*
	* @event
	* @method  onDoubleClickHandler
	*/
	Window.prototype.onDoubleClickHandler = function() {

        var oEvent = eventUtil.getEvent();
		var oSource = eventUtil.getSource(oEvent);
		
		var window = null;
		var target = Window.prototype.objects.get(oSource.id);
		
        if (target instanceof Window) {
        // window receiving event
            window = target;
        }
        else if (target instanceof ActionButton) {
        // button receiving event
            window = target.getParent();
        }

        if (window !== null) {
            if (window.isShrinked()) {
				window.expand();
			}
			else {
				window.shrink();
			}
        }
	};


    /**
    * Sets window title
    *
    * @public
    * @method setTitle
    * @param {String} title window title to set
    */
    Window.prototype.setTitle = function(title) {

        this.windowTitle = title;
    };

    /**
    * Sets window height: windows height = header height + content height. This function should be
    * called from within a parent control (probably panel). Header height is fixed (in this version),
    * so the only thing that is updated is content div height;
    *
    * @public
    * @method setWindowHeight
    * @param {Number} height  height to be set
    */
    Window.prototype.setControlHeight = function(height) {

        this.controlHeight = height;
		
        var contentHeight = height - (this.headerSize) - 1;  // fixed for now :[
        if (contentHeight < 0) {
            contentHeight = 0;
        }
		try {
			this.setHeight(height);
            this.setHeight(contentHeight, this.windowContentDom);
        }
		catch (ex) {}

        if (this.control !== null && this.control.isBuild()) {
        // update width of child control, can be recursive
            if (this.control instanceof Panel) {

                this.control.setPanelHeight(contentHeight);
            }
            else if (this.control instanceof MessUIElement) {

                this.control.setControlHeight(contentHeight - 2); // -2 for border widths
            }
        }
    };

    /**
    * Sets window width. Width is changed on top most window div container
    *
    * @public
    * @method setControlWidth
    * @param  {Number} width  width to be set
    */
    Window.prototype.setControlWidth = function(width) {

        // set this window width
        this.controlWidth = width;
        try {
            this.setWidth(width);
			
            if (this.isHorizontal()) {
           	// update window clone
	            this.windowClone.setWidth(width);
            }
        } catch(ex) {}

        if (this.control !== null && this.control.isBuild()) {
        // update width of child control, can be recursive
            if (this.control instanceof Panel) {
                
                this.control.setPanelWidth(width - 2); // -2 for border widths
            }
            else if (this.control instanceof MessUIElement) {

                this.control.setControlWidth(width - 2); 
            }
        }
    };

    /**
    * Return window minimum height - height of window header
    *
    * @public
    * @method  getMinHeight
    * @return  {Number} window min height
    */
    Window.prototype.getMinHeight = function() {

        if (this.control !== null) {
            return this.control.getMinHeight();
        }
        else {
            return this.headerSize; // dummy min height
        }
    };

    /**
    * Return window maximum height - height of window header and content
    *
    * @public
    * @method getMaxHeight
    * @return {Number}  window max height
    */
    Window.prototype.getMaxHeight = function() {

        if (this.control !== null) {
            return this.control.getMaxHeight();
        }
        else {
            return null;
        }
    };

    /**
    * Returns information about window beeing in shrinked state. True if shrinked, false otherwise.
    *
    * @public
    * @method isShrinked
    * @return {Boolean}  true / false
    */
    Window.prototype.isShrinked = function() {

        return this.shrinked;
    };
    
    /**
    * Returns information about window beeing in maximized state. 
    *
    * @public
    * @method isMaximized
    * @return {Boolean}  true / false
    */
    Window.prototype.isMaximized = function() {

        return this.maximized;
    };

    /**
    * Returns true if parent panel is horizontal. False otherwise.
    *
    * @public
    * @method  isHorizontal
    * @return  {Boolean}  true / false
    */
    Window.prototype.isHorizontal = function() {

        return this.parent.isHorizontal();
    };

    /**
    * Returns true if parent panel is vertical. False otherwise.
    *
    * @public
    * @method  isVertical
    * @return  {Boolean}  true / false
    */
    Window.prototype.isVertical = function() {

        return this.parent.isVertical();
    };

    /**
    * Method called via shrink button - shrinks/expands window control
    *
    * @public
    * @method  shrinkWindow
    */
    Window.prototype.shrinkWindow = function() {

        if (this.isShrinked()) {
            this.expand();
        }
        else {
            this.shrink();
        }
    };

    /**
    * Shrinks window, so it's in minimized state.
    *
    * @public
    * @method  shrink
    */
    Window.prototype.shrink = function() {

        if (this.parent !== null) {
	        // write object instance to hiddenWindow variable
	        //var o = this.domObject;
	        this.windowClone = this.clone(this, new Window(this.windowTitle));
            this.shrinked = true;

            if (this.parent instanceof WindowControl) {
            // parent control responsible for shrinking logic
                this.parent.shrink(this);
            }
            else {
            // window in panel, let it shrink itself
                this.parent.disable();

                if (this.isHorizontal()) {
                    this.shrinkHorizontal();
                }
                else if (this.isVertical()) {
                    this.shrinkVertical();
                }
            }
        }
        else {
        // parent not yet set
            this.shrinked = true;
        }
    };

    /**
    * Shrink horizontal panel.
    *
    * @private
    * @method  shrinkHorizontal
    */
    Window.prototype.shrinkHorizontal = function() {

        var prevSibling = this.getPrevSibling();
        var nextSibling = this.getNextSibling();

        if (prevSibling === null && nextSibling !== null) {
        // 'top-edge' shrinking

                // build 'shrinked' window representation
                this.buildDOMObjectShrinked();

                // update parent panel height
                var parentHeight = this.parent.getHeight();
                var diff = parentHeight - this.headerSize;
                this.parent.setPanelHeight(this.headerSize);

                // update sibling heights 
                var result = this.updateSiblingHeights(nextSibling, diff, "getNextSibling", "+");

                if (result["diff"] > 0 && result["foundNonShrinked"]) {
				// [TODO: handle it here]
				}
				else if (!result["foundNonShrinked"]) {
				// couldn't find non-shrinked sibling, expand neariest (shrinked) sibling
					nextSibling.expand();
				}
        }
        else if (nextSibling === null && prevSibling !== null) {
        // 'bottom-edge' shrinking

                // build 'shrinked' window representation
                this.buildDOMObjectShrinked();

                // update parent panel height
                var parentHeight = this.parent.getHeight();
                var diff = parentHeight - this.headerSize;
                this.parent.setPanelHeight(this.headerSize);

                // update sibling heights
                var result = this.updateSiblingHeights(prevSibling, diff, "getPrevSibling", "+");

                if (result["diff"] > 0 && result["foundNonShrinked"]) {
				// [TODO: handle it here]
				}
				else if (!result["foundNonShrinked"]) {
					prevSibling.expand();
				}    
        }
        else if (nextSibling !== null && prevSibling !== null) {
        // 'middle panel' shrinking
               
				// build 'shrinked' window representation
				this.buildDOMObjectShrinked();
				
				// update parent panel height
				var parentHeight = this.parent.getHeight();
                var diff = parentHeight - this.headerSize;
				this.parent.setPanelHeight(this.headerSize);
				
                var hasExpandedNextSibling = this.hasExpandedSibling(nextSibling, "getNextSibling");
                if (hasExpandedNextSibling) {
                // found 'next' window we can resize
                    this.updateSiblingHeights(nextSibling, diff, "getNextSibling", "+");
                }
                else {
                    var hasExpandedPrevSibling = this.hasExpandedSibling(prevSibling, "getPrevSibling");
                    if (hasExpandedPrevSibling) {
                    // found 'prev' window we can resize
                        this.updateSiblingHeights(prevSibling, diff, "getPrevSibling", "+");
                    }
                    else {
                    // all siblings shrinked, expand first 'next' sibling
                        nextSibling.expand();
                    }
                }
        }
    };
	
	/**
	* Shrinks vertical windows
	*
	* @private
	* @method   shrinkVertical
	*/
	Window.prototype.shrinkVertical = function() {
		
		var prevSibling = this.getPrevSibling();
		var nextSibling = this.getNextSibling();
		
		
		if (prevSibling === null && nextSibling !== null) {
		// left edge shrinking
				
                // update parent panel width
                var parentWidth = this.parent.getWidth();
                var diff = parentWidth - this.headerSize;
                this.parent.setPanelWidth(this.headerSize);
				
                // update sibling heights
                var result = this.updateSiblingWidths(nextSibling, diff, "getNextSibling", "+");

                if (result["diff"] > 0 && result["foundNonShrinked"]) {
				// [TODO: handle it here]
				}
				else if (!result["foundNonShrinked"]) {
				// couldn't find non-shrinked sibling, expand neariest (shrinked) sibling
					nextSibling.expand();
				}

            	// build 'shrinked' window representation
                this.buildDOMObjectShrinked();
        }
		else if (prevSibling !== null && nextSibling === null) {
		// right edge shrinking
		
                // update parent panel width
                var parentWidth = this.parent.getWidth();
                var diff = parentWidth - this.headerSize;
                this.parent.setPanelWidth(this.headerSize);
				
                // update sibling heights
                var result = this.updateSiblingWidths(prevSibling, diff, "getPrevSibling", "+");

                if (result["diff"] > 0 && result["foundNonShrinked"]) {
				// [TODO: handle it here]
				}
				else if (!result["foundNonShrinked"]) {
				// couldn't find non-shrinked sibling, expand neariest (shrinked) sibling
					prevSibling.expand();
				}

            	// build 'shrinked' window representation
                this.buildDOMObjectShrinked();
				
		}
	};

    /**
    * Expands window, returning it to the state before shrinking (minimizing)
    *
    * @public
    * @method  expand
    */
    Window.prototype.expand = function() {

        this.shrinked = false;

        // fill all window fields from previously remembered clone (this.windowClone);
		if (this.windowClone !== null) {
			this.fillFromObject(this.windowClone);
		}
		else {
        // no previous clone present, build expanded object from scratch
            this.buildDOMObject();
            this.attachEventHandlers();
        }

        if (this.parent instanceof WindowControl) {
        // parent control responsible for expanding
            this.parent.expand(this);
        }
        else if (this.parent instanceof Panel) {
        // window in panel, let it shrink itself
            this.parent.enable();
            
            if (this.isHorizontal()) {
                this.expandHorizontal();
            }
            else if (this.isVertical()) {
                this.expandVertical();
            }
        }

        this.parent.replaceControl(this);        
    };
	
	/**
	* Horizontal window  expanding logic
	*
	* @private
	* @method expandHorizontal
	*/
	Window.prototype.expandHorizontal = function() {
	
		var prevSibling = this.getPrevSibling();
		var nextSibling = this.getNextSibling();
		
		if (prevSibling === null && nextSibling !== null) {
		// 'top edge' expanding

            var height = this.getControlHeight();
			var diff = height - this.headerSize;
            this.parent.setPanelHeight(height);

            // update heights of (bottom) sibling panels
            var result = this.updateSiblingHeights(nextSibling, diff, "getNextSibling", "-");

			if (result["diff"] > 0 && result["foundNonShrinked"]) {
			    // check if diff distributed, if not, change height of panel beeing expanded (this)
				this.parent.setPanelHeight( this.parent.getHeight() - diff );
			}
			else if (!result["foundNonShrinked"]) {
			    // will have to check container parent height and fill free space
				this.parent.setPanelHeight( this.parent.getHeight() + this.getContainerFreeSpace());
			}

            this.buildButtonsBox(true);
		}
		else if (nextSibling === null && prevSibling !== null) {
		// 'bottom edge' expanding
		
			var height = this.getControlHeight();
			var diff = height - this.headerSize;
            this.parent.setPanelHeight(height);

            // update heights of (top) sibling panels
            var result = this.updateSiblingHeights(prevSibling, diff, "getPrevSibling", "-");

			// check if diff distributed, if not, change height of panel beeing expanded (this)
			if (result["diff"] > 0 && result["foundNonShrinked"]) {
				this.parent.setPanelHeight( this.parent.getHeight() - diff );
			}
            else if (!result["foundNonShrinked"]) {
                // we have to check container parent height and fill free space
                this.parent.setPanelHeight( this.parent.getHeight() + this.getContainerFreeSpace());
            }

            this.buildButtonsBox(true);
		}
		else if (prevSibling !== null && nextSibling !== null) {
		// 'middle' panel expanding

            var height = this.getControlHeight();
			var diff = height - this.headerSize;
            this.parent.setPanelHeight(height);

            var hasExpandedNextSibling = this.hasExpandedSibling(nextSibling, "getNextSibling");
            if (hasExpandedNextSibling) {
            // found expanded 'next' sibling, update heights
                var result = this.updateSiblingHeights(nextSibling, diff, "getNextSibling", "-");
            }
            else {
                var hasExpandedPrevSibling = this.hasExpandedSibling(prevSibling, "getPrevSibling");
                if (hasExpandedPrevSibling) {
                // found expanded 'prev' sibling, update heights
                    var result = this.updateSiblingHeights(prevSibling, diff, "getPrevSibling", "-");
                }
                else {
                // all siblings in shrinked state, fill up available space
                    this.parent.setPanelHeight( this.parent.getHeight() + this.getContainerFreeSpace() );
                }
            }

            this.buildButtonsBox(true);
        }
	};

    /**
    * Vertical window expanding logic
    *
    * @private
    * @method  expandVertical
    */
    Window.prototype.expandVertical = function() {

        var prevSibling = this.getPrevSibling();
        var nextSibling = this.getNextSibling();

        if (prevSibling === null && nextSibling !== null) {
        // left edge expanding

            var width = this.getControlWidth();
            var diff = width - this.headerSize;
			this.parent.setPanelWidth(width);

            // update widths of (right) sibling panels
            var result = this.updateSiblingWidths(nextSibling, diff, "getNextSibling", "-");

			if (result["diff"] > 0 && result["foundNonShrinked"]) {
			    // check if diff distributed, if not, change height of panel beeing expanded (this)
				this.parent.setPanelWidth( this.parent.getWidth() - diff );
			}
			else if (!result["foundNonShrinked"]) {
			    // will have to check container parent height and fill free space
				this.parent.setPanelWidth( this.parent.getWidth() + this.getContainerFreeSpace());
			}

			this.buildButtonsBox(true);
        }
		else if (prevSibling !== null && nextSibling === null) {
		// right edge expanding
		
            var width = this.getControlWidth();
            var diff = width - this.headerSize;
			this.parent.setPanelWidth(width);

            // update widths of (right) sibling panels
            var result = this.updateSiblingWidths(prevSibling, diff, "getPrevSibling", "-");

			if (result["diff"] > 0 && result["foundNonShrinked"]) {
			    // check if diff distributed, if not, change height of panel beeing expanded (this)
				this.parent.setPanelWidth( this.parent.getWidth() - diff );
			}
			else if (!result["foundNonShrinked"]) {
			    // will have to check container parent height and fill free space
				this.parent.setPanelWidth( this.parent.getWidth() + this.getContainerFreeSpace());
			}

			this.buildButtonsBox(true);
		}
    };

    /**
    * Updates heights of this window (non-shrinked) siblings. Super korwa method ]:->
    *
    * @private
    * @method  updateSiblingHeights
    * @param   {MessUIElement) startSibling   sibling we start resizing from
    * @param   {Number} diff   height to redistribute among non-shrinked siblings
    * @param   {String}  getNextElementMethod    the method used to aquire acces to next sibling in line (next or prev)
    * @param   {String}  calc   calculation method,  + or -
    * @return  {Array}   assiociate array containing 2 elements
    *                    ["diff"]: non-redistributed height
    *                    ["foundNonShrinked"]: boolean, true if found at least one non-shrinked window
    */
    Window.prototype.updateSiblingHeights = function(startSibling, diff, getNextElementMethod, calc) {

        var foundNonShrinked = false;
		var _sibling = startSibling;
        while (_sibling !== null) {
			
			if (_sibling instanceof Window) {
			// handle window siblings
	            _sibling.buildButtonsBox(true);
	
	            if (_sibling.isShrinked()) {
	                eval("_sibling = _sibling."+getNextElementMethod+"();");
					continue;
				}
			}

            if (_sibling instanceof Panel) {
                eval("diff = _sibling.setPanelHeight(_sibling.getHeight()"+calc+"diff, true);");   
            }
            else {
                eval("diff = _sibling.parent.setPanelHeight(_sibling.parent.getHeight()"+calc+"diff, true);");
			}
            foundNonShrinked = true;

            if (diff == 0) {
			    break;
			}
			else {
			    eval("_sibling = _sibling."+getNextElementMethod+"();");
            }
        }
        
        var result = new Array();
            result["diff"] = diff;
            result["foundNonShrinked"] = foundNonShrinked;

        return result;   
    };
	
	   /**
	    * Updates widths of this window (non-shrinked) siblings. Super korwa method ]:->
	    *
	    * @private
	    * @method  updateSiblingWidths
	    * @param   {MessUIElement) startSibling   sibling we start resizing from
	    * @param   {Number} diff  width to redistribute among non-shrinked siblings
	    * @param   {String}  getNextElementMethod    the method used to aquire acces to next sibling in line (next or prev)
	    * @param   {String}  calc   calculation method,  + or -
	    * @return  {Array}   assiociate array containing 2 elements
	    *                    ["diff"]: non-redistributed width
	    *                    ["foundNonShrinked"]: boolean, true if found at least one non-shrinked window
	    */
    Window.prototype.updateSiblingWidths = function(startSibling, diff, getNextElementMethod, calc) {

        var foundNonShrinked = false;
		var _sibling = startSibling;
        while (_sibling !== null) {

            if (_sibling instanceof Window) {
			// handle window siblings
	            _sibling.buildButtonsBox(true);

	            if (_sibling.isShrinked()) {
	                eval("_sibling = _sibling."+getNextElementMethod+"();");
					continue;
				}
			}

            if (_sibling instanceof Panel) {
                eval("diff = _sibling.setPanelWidth(_sibling.getWidth()"+calc+"diff, true);");
            }
            else {
                eval("diff = _sibling.parent.setPanelWidth(_sibling.parent.getWidth()"+calc+"diff, true);");
			}
            foundNonShrinked = true;

            if (diff == 0) {
			    break;
			}
			else {
			    eval("_sibling = _sibling."+getNextElementMethod+"();");
            }
        }
        var result = new Array();
            result["diff"] = diff;
            result["foundNonShrinked"] = foundNonShrinked;

        return result;   
    };	

    /**
    * Checks if element has any expanded sibling
    *
    * @private
    * @method  hasExpandedSibling
    * @param   {MessUIElement} sibling   sibling we start the search from
    * @param   {String} getNextElementMethod  method to use to obtain next element in line
    * @return  {Boolean}  true / false
    */
    Window.prototype.hasExpandedSibling = function(sibling, getNextElementMethod) {

        var _sibling = sibling;
        while (_sibling !== null) {
            if (!_sibling.isShrinked()) {
                return true;
            }
            else {
                eval("_sibling = _sibling."+getNextElementMethod+"();");
            }
        }
        return false;
    };

    /**
    * Get container free space - not occupied by windows
    *
    * @private
    * @method  getContainerFreeSpace
    * @return  {Number} free space in container
    */
    Window.prototype.getContainerFreeSpace = function() {

        var containerPanel = this.getParent().getParent();
        return containerPanel.getHeight() - containerPanel.getTotalHeight();    
    };

	
    /**
    * Replaces panel child control.
    *
    * @public
    * @method  replaceControl
    * @param  {MessUIElement} control  replacement control
    */
    Window.prototype.replaceControl = function(control) {

        this.control = control

        // update windowContet dom tree
        this.windowContentDom.removeChild(this.domObject.firstChild);
        this.windowContentDom.appendChild(control.render());
    };

    /**
    * Return content container height
    *
    * @public
    * @method  getControlContentHeight
    * @return  {Number} height in px of window content height
    */
    Window.prototype.getControlContentHeight = function() {

        return this.parent.getHeight() - this.headerSize - 1;
    };

    /**
    * Return content container width
    *
    * @public
    * @method  getControlContentWidth
    * @return  {Number} width in px of window content width
    */
    Window.prototype.getControlContentWidth = function() {

        return this.parent.getWidth() - 2;  // -2  for border widths
    };
    
     
     
	/**
	 * MouseOver flag setter
	 * 
	 * @public
	 * @method  setMouseOver
	 * @param   {Boolean} true / false
	 */
	Window.prototype.setMouseOver = function(mode) {
		
		this.mouseOver = mode;
	};
	
	/**
	 * MouseOver flag getter
	 * 
	 * @public
	 * @method  hasMouseOver
	 * @return  {Boolean} true / fasle
	 */
	Window.prototype.hasMouseOver = function() {
		
		return this.mouseOver;
	};
	
	/**
	 * Header size property getter
	 * 
	 * @public
	 * @method  getHeaderSize
	 * @return  {Number} size in pixels of window header
	 */
	Window.prototype.getHeaderSize = function() {
		
		return this.headerSize;	
	};
	
	/**
	 * Header size property setter
	 * 
	 * @public
	 * @method  setHeaderSize
	 * @param   {Number} size   header size to set
	 */
	Window.prototype.setHeaderSize = function(size) {
		
		this.headerSize = new Number(size);
	};
	
        

    /**
    * called from maximize button - maximize/normalize window
    *
    * @public
    * @method  maximizeWindow
    */
    Window.prototype.maximizeWindow = function() {

        if (this.isMaximized()) {
            this.normalize();
        }
        else {
            this.maximize();
        }
    };

     
     /**
      * Method responsible for closing window logic
      * 
      * @public
      * @method  closeWindow
      */
	Window.prototype.close = function() {

        // close inner control
        this.closeInnerControl();
        // destroy buttons
        this.destroyButtons();
        // run parent panel closing logic
        this.parent.close();
    };

    /**
    * Close and destroy inner control (can be recursive)
    *
    * @private
    * @method  closeInnerControl
    */
    Window.prototype.closeInnerControl = function() {

        if (this.control) {
        // close inner control
            this.control.close();
            try {
                this.control.destroy();
            }
            catch (ex) {}
        }
    }

    /**
    * Destroy any existing buttons
    *
    * @private
    * @method  destroyButtons
    */
    Window.prototype.destroyButtons = function() {

        if (!this.buttons.isEmpty()) {
            for (var it = this.buttons.iterator(); it.hasNext();) {
                it.next().destroy();
            }
        }
    }

    /**
    * Window icon property setter
    *
    * @public
    * @method  setIcon
    * @param   {String} icon   icon file name
    */
    Window.prototype.setIcon = function(icon) {

        this.windowIcon = icon;
    }

    /**
    * Return content container height
    *
    * @public
    * @method  getControlContentHeight
    * @return  {Number} height in px of window content height
    */
    Window.prototype.getControlContentHeight = function() {

        return this.parent.getHeight() - this.headerSize - 1;
    };

    /**
    * Return content container width
    *
    * @public
    * @method  getControlContentWidth
    * @return  {Number} width in px of window content width
    */
    Window.prototype.getControlContentWidth = function() {

        return this.parent.getWidth() - 2;  // -2  for border widths
    };





	





